#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define MAX_CLIENTS 10

struct ClientInfo 
{
    int sockfd;
    struct sockaddr_in addr;
};

int main(void) 
{
    // 创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("socket");
        return -1;
    }

    // 绑定
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(50000);
    addr.sin_addr.s_addr = INADDR_ANY;

    int ret = bind(sockfd, (struct sockaddr*)(&addr), sizeof(addr));
    if (ret < 0) {
        perror("bind");
        return -1;
    }

    // 监听
    ret = listen(sockfd, 5);
    if (ret < 0) {
        perror("listen");
        return -1;
    }

    // 初始化客户端数据
    struct ClientInfo cinfo[MAX_CLIENTS];
    memset(cinfo, 0 , sizeof(cinfo));

    // 创建文件描述符集合并将监听套接字加入
    fd_set read_fds;
    FD_ZERO(&read_fds);
    FD_SET(sockfd, &read_fds);

    int max_fd = sockfd; // 最大文件描述符

    while (1) {
        // 复制文件描述符集合
        fd_set temp_fds = read_fds;

        // 使用 select() 函数监听文件描述符
        ret = select(max_fd + 1, &temp_fds, NULL, NULL, NULL);
        if (ret < 0) {
            perror("select");
            break;
        }

        // 检查监听套接字是否有新连接
        if (FD_ISSET(sockfd, &temp_fds)) 
		{
            struct sockaddr_in clientaddr;
            socklen_t len = sizeof(clientaddr);
            int clientfd = accept(sockfd, (struct sockaddr *)(&clientaddr), &len);
            if (clientfd < 0) 
			{
                perror("accept");
                continue;
            }
            printf("客户端IP: %s\n", inet_ntoa(clientaddr.sin_addr));

            // 将新连接的已连接套接字加入文件描述符集合
            FD_SET(clientfd, &read_fds);

            // 更新最大文件描述符
            if (clientfd > max_fd) 
			{
                max_fd = clientfd;
            }

            // 遍历客户端信息数组，找到空闲位置存储客户端信息
            for (int i = 0; i < MAX_CLIENTS; i++) 
			{
                if (cinfo[i].sockfd == 0) 
				{ // 表示没有被使用
                    cinfo[i].sockfd = clientfd;
                    cinfo[i].addr = clientaddr;
                    break;
                }
            }
        }

        // 遍历已连接套接字，处理可读数据
        for (int i = 0; i < MAX_CLIENTS; i++) 
		{
            int clientfd = cinfo[i].sockfd;
            if (clientfd == 0) 
			{
                continue; // 跳过未使用的位置
            }

            if (FD_ISSET(clientfd, &temp_fds)) 
			{
                char recvbuffer[256] = {0};
                int ret = read(clientfd, recvbuffer, sizeof(recvbuffer));
                if (ret <= 0) 
				{
                    // 客户端掉线，关闭套接字并从文件描述符集合中移除
                    perror("read/客户端掉线");
                    close(clientfd);
                    FD_CLR(clientfd, &read_fds);

                    // 清空客户端信息数组
                    cinfo[i].sockfd = 0;
                    memset(&cinfo[i].addr, 0, sizeof(struct sockaddr_in));

                    continue;
                }

                // 输出客户端数据
                printf("%s\n", recvbuffer);

                // 解析：to:192.168.13.25,data:xxxx 把数据xxx转发给192.168.13.25对应的客户端
                if (strncmp(recvbuffer, "to:", 3) == 0) 
				{
                    char ip[32] = {0};
                    char data[128] = {0};
                    sscanf(recvbuffer, "to:%[^,],data:%s", ip, data);
                    unsigned int netip = inet_addr(ip);

                    // 遍历已连接的客户端信息列表，发送数据给匹配的客户端
                    for (int j = 0; j < MAX_CLIENTS; j++) 
					{
                        if (cinfo[j].sockfd != 0 && cinfo[j].addr.sin_addr.s_addr == netip) 
						{
                            send(cinfo[j].sockfd, data, strlen(data), 0);
                        }
                    }
                }
            }
        }
    }

    // 关闭套接字
    close(sockfd);

    return 0;
}


